package myzzyl.interceptor;

import cn.hutool.core.text.AntPathMatcher;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import context.JwtUserContext;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import myzzyl.constants.CommonStrField;
import myzzyl.constants.ErrorConstants;
import myzzyl.domain.pojo.JwtUser;
import myzzyl.exception.BusinessException;
import myzzyl.properties.JwtProperties;
import myzzyl.utils.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import java.util.List;


/**
 * 登录拦截器
 */
@Slf4j
@Component
public class LoginInterceptor implements HandlerInterceptor {


    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private JwtProperties jwtProperties;

    private final AntPathMatcher antPathMatcher = new AntPathMatcher();


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 判断是否是静态资源或者是跨域预检请求等不是controller控制器中的请求
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }
        // 获取jwt令牌
        String jwt = request.getHeader(jwtProperties.getToken());
        log.info("拦截未登录请求:{}", jwt);

        // 校验jwt
        if (JwtUtil.validateJwt(jwtProperties.getSecret(), jwt)) {
            // 校验通过，解析获取jwtUser
            JwtUser jwtUser = JwtUtil.parseJwtToJwtUser(jwtProperties.getSecret(), jwt);
            // 判断是否与redis中的一致，双重校验
            String userToken = stringRedisTemplate.opsForValue()
                    .get(CommonStrField.USER_TOKEN.getStr() + jwtUser.getId());
            if(!ObjectUtil.equal(userToken, jwt)) {
                throw new BusinessException(ErrorConstants.USER_IS_NOT_LOGIN);
            }
            // 获取请求方式和请求url拼接，并使用antPathMatcher做匹配
            String resourceUrl = request.getMethod() + request.getRequestURI();

            // 从redis中取出当前用户可以访问的资源
            String resourceUrls = stringRedisTemplate.opsForValue()
                    .get(CommonStrField.USER_RESOURCE.getStr() + jwtUser.getId());

            // 将resourceUrls转换为list集合用于遍历匹配
            if (ObjectUtil.isNotEmpty(resourceUrls)) {
                List<String> resourceUrlsList = JSONUtil.toList(resourceUrls, String.class);
                for (String url : resourceUrlsList) {
                    if (antPathMatcher.match(url, resourceUrl)) {
                        return true;
                    }
                }
            }

            // 没有匹配上抛出权限不足异常
            throw new BusinessException(ErrorConstants.FORBIDDEN);
        }else {
            // 校验不通过，抛出用户未登录异常
            throw new BusinessException(ErrorConstants.USER_IS_NOT_LOGIN);
        }
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("去除jwtUser");
        JwtUserContext.removeJwtUser();
    }
}
